// 引入IIC通讯所需的Wire库文件
#include <Wire.h>
// 引入驱动OLED0.96所需的库
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// 引入霍尔编码器所需要的定时器时间库
#include <TimerOne.h>

#define SCREEN_WIDTH 128 // 设置OLED宽度,单位:像素
#define SCREEN_HEIGHT 64 // 设置OLED高度,单位:像素
// 自定义重置引脚,虽222222222222222222222222222222222222222223然教程未使用,但却是Adafruit_SSD1306库文件所必需的
#define OLED_RESET 4
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

float v;
volatile long counter_val0 = 0;
volatile long counter_val1 = 0; // 该变量用于存储编码器的值，所以用类型修饰符volatile；
int flag = 0;                   // 定时器标志；

void setup()
{
  // put your setup code here, to run once:
  // 初始化OLED并设置其IIC地址为 0x3C
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  // 霍尔编码器测速初始化
  delay(2000);

  pinMode(2, INPUT); // 设置为输入模式，并且2,3号引脚是中断口0,1；
  pinMode(3, INPUT); // 传入霍尔编码器输入的信号

  Serial.begin(115200);                 // 初始化波特率为115200// 连接串口通信
  attachInterrupt(0, counter0, RISING); // 设置编码器A相位上升沿中断
  attachInterrupt(1, counter1, RISING); // 设置编码器B相位上升沿中断
  Timer1.initialize(50000);             // 设置定时器中断时间，单位微秒 ，这里是50毫秒
  Timer1.attachInterrupt(timerIsr);     // 打开定时器中断
  interrupts();                         // 打开外部中断
}

void loop()
{
  // put your main code here, to run repeatedly:

  // 霍尔编码器测速部分
  long lTemp = 0; //定义临时存储数据变量
  if (flag == 1)  //判断是否发生定时器中断，这里是50ms发生一次
  {
    flag = 0; //清除标记
  }

  // OLED显示器显示部分
  words_display();
  display.display();
}
//外部中断处理函数
void counter0()
{
  counter_val0++; //每一个中断加一
}
void counter1()
{
  counter_val1++; //每一个中断加一
}
//定时器中断处理函数
void timerIsr()
{
  flag = 1; //定时时间达到标志

  //速度计算公式
  v = 60 * 20 * counter_val0 * 0.063 / 333.0; //这里的单位是转每分钟：r/min

  Serial.println(v); // 将计算结果通过串口通信传到电脑
  counter_val0 = 0;
  counter_val1 = 0; //清空该时间段内的脉冲数
  return v;
}
void words_display()
{
  // 清除屏幕
  display.clearDisplay();

  // 设置字体颜色,白色可见
  display.setTextColor(WHITE);

  //设置字体大小
  display.setTextSize(1.5); // 高10个像素点

  // 打印小组名字
  display.setCursor(0, 0);
  display.print("Ur Code Never Error!");

  //打印自开发板重置以来启动的秒数：
  display.setCursor(0, 10);
  display.print("Time: ");
  // millis可以记录arduino开机时长单位ms
  display.print(millis() / 1000);
  display.print(" s");

  display.setCursor(0, 20);
  display.print("Velocity:");
  display.setCursor(0, 30);
  //设置字体大小
  display.setTextSize(2); // 高10个像素点
  display.print(v);
  display.setTextSize(1.5); // 高10个像素点
  display.setCursor(60, 35);
  display.print("m/s");
}

//参考：https://blog.csdn.net/xwwwj/article/details/104656560
// http://www.taichi-maker.com/homepage/reference-index/display-reference-index/arduino-oled-application/
// wire库教程参考http://www.taichi-maker.com/homepage/reference-index/arduino-library-index/wire-library/
